package com.b.sts.service.impl;

import cn.hutool.core.date.DateUtil;
import com.b.sts.entity.UserEntity;
import com.b.sts.enums.RedisEnum;
import com.b.sts.enums.TokenEnum;
import com.b.sts.enums.UserTypeEnum;
import com.b.sts.exception.FailException;
import com.b.sts.exception.OauthException;
import com.b.sts.mapper.UserMapper;
import com.b.sts.request.UserRequest;
import com.b.sts.service.AuthService;
import com.b.sts.service.UserService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.Objects;
import java.util.Optional;

/**
 * @author boy
 * @since 2022/10/28
 */
@Service
public class AuthServiceImpl implements AuthService {
    @Resource
    UserMapper userMapper;
    @Resource
    UserService userService;

    private final String JWT_SECRET = TokenEnum.JWT_SECRET.getValue();
    private final String TOKEN_PREFIX = RedisEnum.TOKEN_PREFIX.getValue();

    @Override
    public String login(UserRequest request) {
        QueryWrapper<UserEntity> wrapper = new QueryWrapper<>();
        wrapper.eq("account", request.getAccount())
                .eq("password", request.getPassword());
        UserEntity user = Optional.ofNullable(userMapper.selectOne(wrapper))
                .orElseThrow(() -> new FailException("账号密码错误或未注册"));
        //记住密码给30天，否则12小时
        if (Objects.equals(request.getRemember(), true)) {
            return this.createToken(user.getId());
        } else {
            return this.createToken(user.getId());
        }
    }


    @Override
    public String register(UserRequest request) {
        QueryWrapper<UserEntity> wrapper = new QueryWrapper<>();
        wrapper.eq("account", request.getAccount());
        if (userMapper.selectOne(wrapper) != null) {
            throw new FailException("注册失败，账号已存在");
        }
        UserEntity user = new UserEntity();
        BeanUtils.copyProperties(request, user);
        user.setCreateTime(new Date());
        if ("graduate".equals(request.getType())) {
            if (!userService.isGraduate(user)) {
                throw new FailException("非毕业生");
            }
        }
        if (userMapper.insert(user) > 0) {
            return this.createToken(user.getId());
        }
        throw new FailException("注册失败");
    }


    @Override
    public String createToken(Integer uid) {
        Claims claims = Jwts.claims()
                .setId(String.valueOf(uid))
                .setIssuedAt(new Date())
                .setExpiration(DateUtil.offsetDay(new Date(), 7));
        return Jwts.builder().setClaims(claims).signWith(SignatureAlgorithm.HS512, JWT_SECRET).compact();
    }

    @Override
    public Integer getUserId() {
        String token = this.getHeaderToken();
        Claims claims = this.getClaimsFromToken(token);
        return Integer.valueOf(claims.getId());
    }

    @Override
    public UserEntity getUser() {
        Integer userId = this.getUserId();
        UserEntity user = Optional.ofNullable(userMapper.selectById(userId))
                .orElseThrow(() -> new FailException("用户不存在"));
        user.setPassword(null);
        return user;
    }


    private Claims getClaimsFromToken(String token) {
        return Jwts.parser().setSigningKey(JWT_SECRET).parseClaimsJws(token).getBody();
    }

    private String getHeaderToken() {
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = requestAttributes == null ? null : requestAttributes.getRequest();
        if (request == null) {
            throw new OauthException("验证失败");
        }
        return Optional.ofNullable(request.getHeader(TokenEnum.HEADER.getValue()))
                .orElseThrow(() -> new OauthException("未携带令牌"))
                .substring(TokenEnum.TOKEN_PREFIX.getValue().length());
    }


}